package com.lazycat.leetcode.editor.cn;
//2023-05-24 20:31:55
//给你一棵由 n 个顶点组成的无向树，顶点编号从 1 到 n。青蛙从 顶点 1 开始起跳。规则如下： 
//
// 
// 在一秒内，青蛙从它所在的当前顶点跳到另一个 未访问 过的顶点（如果它们直接相连）。 
// 青蛙无法跳回已经访问过的顶点。 
// 如果青蛙可以跳到多个不同顶点，那么它跳到其中任意一个顶点上的机率都相同。 
// 如果青蛙不能跳到任何未访问过的顶点上，那么它每次跳跃都会停留在原地。 
// 
//
// 无向树的边用数组 edges 描述，其中 edges[i] = [ai, bi] 意味着存在一条直接连通 ai 和 bi 两个顶点的边。 
//
// 返回青蛙在 t 秒后位于目标顶点 target 上的概率。与实际答案相差不超过 10⁻⁵ 的结果将被视为正确答案。 
//
// 
//
// 示例 1： 
//
// 
//
// 
//输入：n = 7, edges = [[1,2],[1,3],[1,7],[2,4],[2,6],[3,5]], t = 2, target = 4
//输出：0.16666666666666666 
//解释：上图显示了青蛙的跳跃路径。青蛙从顶点 1 起跳，第 1 秒 有 1/3 的概率跳到顶点 2 ，然后第 2 秒 有 1/2 的概率跳到顶点 4，因此青蛙
//在 2 秒后位于顶点 4 的概率是 1/3 * 1/2 = 1/6 = 0.16666666666666666 。 
// 
//
// 示例 2： 
//
// 
//
// 
//输入：n = 7, edges = [[1,2],[1,3],[1,7],[2,4],[2,6],[3,5]], t = 1, target = 7
//输出：0.3333333333333333
//解释：上图显示了青蛙的跳跃路径。青蛙从顶点 1 起跳，有 1/3 = 0.3333333333333333 的概率能够 1 秒 后跳到顶点 7 。 
// 
//
// 
//
// 
//
// 提示： 
//
// 
// 1 <= n <= 100 
// edges.length == n - 1 
// edges[i].length == 2 
// 1 <= ai, bi <= n 
// 1 <= t <= 50 
// 1 <= target <= n 
// 
//
// Related Topics 树 深度优先搜索 广度优先搜索 图 👍 94 👎 0

import java.util.*;

class FrogPositionAfterTSeconds {
    public static void main(String[] args) {
        //创建该题目的对象方便调用
        Solution solution = new FrogPositionAfterTSeconds().new Solution();
    }
    //leetcode submit region begin(Prohibit modification and deletion)
class Solution {
    public double frogPosition(int n, int[][] edges, int t, int target) {

        //青蛙🐸访问过路径标记
        boolean[] visit = new boolean[n+1];
        Map<Integer,List<Integer>> path = new HashMap<>();

        //初始化图
        for(int id = 1;id<=n;id++){
            path.put(id,new ArrayList<>());
        }

        //构建图
        for(int[] edge : edges){
            path.get(edge[0]).add(edge[1]);
            path.get(edge[1]).add(edge[0]);
        }

        //青蛙从1起跳
        visit[1] = true;


        return dfs(1,visit,path,t,target,1.0);
    }

    private double dfs(int cur,boolean[] visit,Map<Integer,List<Integer>> path,int time,int target,double factor){

        //跳跃次数结束
        if (time == 0){
            return cur == target ? factor : 0;
        }

        Set<Integer> set = new HashSet<>();

        //统计当前位置能跳过去的位置
        for(int val : path.get(cur)){
            if(!visit[val]){
                set.add(val);
            }
        }
        //没有能跳过去的位置原地跳
        if(set.isEmpty()){
            return cur == target ? factor : 0;
        }
        //跳到目标位置
        if(cur == target){
            return 0;
        }

        double ans = 0;

        //计算当前的概率
        double nextFactor = factor/set.size();

        //回溯
        for(int val : set){
            visit[val] = true;
            ans += dfs(val,visit,path,time-1,target,nextFactor);
            visit[val] = false;
        }

        return ans;
    }
}
//leetcode submit region end(Prohibit modification and deletion)

}